/**
Copyright: Copyright (c) 2017-2019 Andrey Penechko.
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: Andrey Penechko.
*/
module be.asmtest.mov;

import be.asmtest.utils;

void testMov(CodegenTester tester)
{
	// Mov reg8, reg8
	foreach (Register regA; Register.min..RegisterMax) tester.movb(regA, Register.min);
	foreach (Register regB; Register.min..RegisterMax) tester.movb(Register.min, regB);
	tester.assertHexAndReset("88C088C188C288C34088C44088C54088C64088C74188C04188C14188C24188C34188C44188C54188C64188C788C088C888D088D84088E04088E84088F04088F84488C04488C84488D04488D84488E04488E84488F04488F8");

	// Mov reg16, reg16
	foreach (Register regA; Register.min..RegisterMax) tester.movw(regA, Register.min);
	foreach (Register regB; Register.min..RegisterMax) tester.movw(Register.min, regB);
	tester.assertHexAndReset("6689C06689C16689C26689C36689C46689C56689C66689C7664189C0664189C1664189C2664189C3664189C4664189C5664189C6664189C76689C06689C86689D06689D86689E06689E86689F06689F8664489C0664489C8664489D0664489D8664489E0664489E8664489F0664489F8");

	// Mov reg32, reg32
	foreach (Register regA; Register.min..RegisterMax) tester.movd(regA, Register.min);
	foreach (Register regB; Register.min..RegisterMax) tester.movd(Register.min, regB);
	tester.assertHexAndReset("89C089C189C289C389C489C589C689C74189C04189C14189C24189C34189C44189C54189C64189C789C089C889D089D889E089E889F089F84489C04489C84489D04489D84489E04489E84489F04489F8");

	// Mov reg64, reg64
	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, Register.min);
	foreach (Register regB; Register.min..RegisterMax) tester.movq(Register.min, regB);
	tester.assertHexAndReset("4889C04889C14889C24889C34889C44889C54889C64889C74989C04989C14989C24989C34989C44989C54989C64989C74889C04889C84889D04889D84889E04889E84889F04889F84C89C04C89C84C89D04C89D84C89E04C89E84C89F04C89F8");

	// Mov reg8, imm8
	foreach (Register regA; Register.min..RegisterMax) tester.movb(regA, Imm8(0x24));
	tester.assertHexAndReset("B024B124B224B32440B42440B52440B62440B72441B02441B12441B22441B32441B42441B52441B62441B724");

	// Mov reg16, imm16
	foreach (Register regA; Register.min..RegisterMax) tester.movw(regA, Imm16(0x2436));
	tester.assertHexAndReset("66B8362466B9362466BA362466BB362466BC362466BD362466BE362466BF36246641B836246641B936246641BA36246641BB36246641BC36246641BD36246641BE36246641BF3624");

	// Mov reg32, imm32
	foreach (Register regA; Register.min..RegisterMax) tester.movd(regA, Imm32(0x24364758));
	tester.assertHexAndReset("B858473624B958473624BA58473624BB58473624BC58473624BD58473624BE58473624BF5847362441B85847362441B95847362441BA5847362441BB5847362441BC5847362441BD5847362441BE5847362441BF58473624");

	// Mov reg64, imm32
	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, Imm32(0x24364758));
	tester.assertHexAndReset("48C7C05847362448C7C15847362448C7C25847362448C7C35847362448C7C45847362448C7C55847362448C7C65847362448C7C75847362449C7C05847362449C7C15847362449C7C25847362449C7C35847362449C7C45847362449C7C55847362449C7C65847362449C7C758473624");

	// Mov reg64, imm64
	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, Imm64(0x24364758AABBCCDD));
	tester.assertHexAndReset("48B8DDCCBBAA5847362448B9DDCCBBAA5847362448BADDCCBBAA5847362448BBDDCCBBAA5847362448BCDDCCBBAA5847362448BDDDCCBBAA5847362448BEDDCCBBAA5847362448BFDDCCBBAA5847362449B8DDCCBBAA5847362449B9DDCCBBAA5847362449BADDCCBBAA5847362449BBDDCCBBAA5847362449BCDDCCBBAA5847362449BDDDCCBBAA5847362449BEDDCCBBAA5847362449BFDDCCBBAA58473624");

	// Mov reg8 mem8
	foreach (Register regA; Register.min..RegisterMax) tester.movb(regA, memAddrDisp32(0x55667788));
	tester.assertHexAndReset("8A0425887766558A0C25887766558A1425887766558A1C2588776655408A242588776655408A2C2588776655408A342588776655408A3C2588776655448A042588776655448A0C2588776655448A142588776655448A1C2588776655448A242588776655448A2C2588776655448A342588776655448A3C2588776655");

	// Mov reg16, mem16
	foreach (Register regA; Register.min..RegisterMax) tester.movw(regA, memAddrDisp32(0x55667788));
	tester.assertHexAndReset("668B042588776655668B0C2588776655668B142588776655668B1C2588776655668B242588776655668B2C2588776655668B342588776655668B3C258877665566448B04258877665566448B0C258877665566448B14258877665566448B1C258877665566448B24258877665566448B2C258877665566448B34258877665566448B3C2588776655");

	// Mov reg32, mem32
	foreach (Register regA; Register.min..RegisterMax) tester.movd(regA, memAddrDisp32(0x55667788));
	tester.assertHexAndReset("8B0425887766558B0C25887766558B1425887766558B1C25887766558B2425887766558B2C25887766558B3425887766558B3C2588776655448B042588776655448B0C2588776655448B142588776655448B1C2588776655448B242588776655448B2C2588776655448B342588776655448B3C2588776655");

	// Mov reg64, mem64
	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrDisp32(0x55667788));
	tester.assertHexAndReset("488B042588776655488B0C2588776655488B142588776655488B1C2588776655488B242588776655488B2C2588776655488B342588776655488B3C25887766554C8B0425887766554C8B0C25887766554C8B1425887766554C8B1C25887766554C8B2425887766554C8B2C25887766554C8B3425887766554C8B3C2588776655");

	// Mov mem8, reg8
	foreach (Register regA; Register.min..RegisterMax) tester.movb(memAddrDisp32(0x55667788), regA);
	tester.assertHexAndReset("88042588776655880C258877665588142588776655881C2588776655408824258877665540882C2588776655408834258877665540883C2588776655448804258877665544880C2588776655448814258877665544881C2588776655448824258877665544882C2588776655448834258877665544883C2588776655");

	// Mov mem16, reg16
	foreach (Register regA; Register.min..RegisterMax) tester.movw(memAddrDisp32(0x55667788), regA);
	tester.assertHexAndReset("668904258877665566890C2588776655668914258877665566891C2588776655668924258877665566892C2588776655668934258877665566893C25887766556644890425887766556644890C25887766556644891425887766556644891C25887766556644892425887766556644892C25887766556644893425887766556644893C2588776655");

	// Mov mem32, reg32
	foreach (Register regA; Register.min..RegisterMax) tester.movd(memAddrDisp32(0x55667788), regA);
	tester.assertHexAndReset("89042588776655890C258877665589142588776655891C258877665589242588776655892C258877665589342588776655893C2588776655448904258877665544890C2588776655448914258877665544891C2588776655448924258877665544892C2588776655448934258877665544893C2588776655");

	// Mov mem64, reg64
	foreach (Register regA; Register.min..RegisterMax) tester.movq(memAddrDisp32(0x55667788), regA);
	tester.assertHexAndReset("488904258877665548890C2588776655488914258877665548891C2588776655488924258877665548892C2588776655488934258877665548893C25887766554C890425887766554C890C25887766554C891425887766554C891C25887766554C892425887766554C892C25887766554C893425887766554C893C2588776655");

	// Mov mem8, imm8
	tester.movb(memAddrDisp32(0x55667788), Imm8(0xAA));
	tester.assertHexAndReset("C6042588776655AA");

	// Mov mem16, imm16
	tester.movw(memAddrDisp32(0x55667788), Imm16(0xAABB));
	tester.assertHexAndReset("66C7042588776655BBAA");

	// Mov mem32, imm32
	tester.movd(memAddrDisp32(0x55667788), Imm32(0xAABBCCDD));
	tester.assertHexAndReset("C7042588776655DDCCBBAA");

	// Mov mem64 imm32
	// mov QWORD PTR [rsp-8], 0xffffffffaabbccdd
	tester.movq(memAddrBaseDisp8(Register.SP, cast(ubyte)(-8)), Imm32(0xAABBCCDD)); // -8
	tester.assertHexAndReset("48C74424F8DDCCBBAA");


	// test memory encoding
	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrDisp32(0x11223344));
	tester.assertHexAndReset("488B042544332211488B0C2544332211488B142544332211488B1C2544332211488B242544332211488B2C2544332211488B342544332211488B3C25443322114C8B0425443322114C8B0C25443322114C8B1425443322114C8B1C25443322114C8B2425443322114C8B2C25443322114C8B3425443322114C8B3C2544332211");

	foreach (Register regA; Register.min..RegisterMax) if (regA != Register.SP) tester.movq(regA, memAddrIndexDisp32(regA, SibScale(0), 0x11223344));
	tester.assertHexAndReset("488B040544332211488B0C0D44332211488B141544332211488B1C1D44332211488B2C2D44332211488B343544332211488B3C3D443322114E8B0405443322114E8B0C0D443322114E8B1415443322114E8B1C1D443322114E8B2425443322114E8B2C2D443322114E8B3435443322114E8B3C3D44332211");

	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrBase(regA));
	tester.assertHexAndReset("488B00488B09488B12488B1B488B2424488B6D00488B36488B3F4D8B004D8B094D8B124D8B1B4D8B24244D8B6D004D8B364D8B3F");

	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrBaseDisp32(regA, 0x11223344));
	tester.assertHexAndReset("488B8044332211488B8944332211488B9244332211488B9B44332211488BA42444332211488BAD44332211488BB644332211488BBF443322114D8B80443322114D8B89443322114D8B92443322114D8B9B443322114D8BA424443322114D8BAD443322114D8BB6443322114D8BBF44332211");

	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrBaseIndex(regA, regA == Register.SP ? Register.AX : regA, SibScale(1)));
	tester.assertHexAndReset("488B0440488B0C49488B1452488B1C5B488B2444488B6C6D00488B3476488B3C7F4F8B04404F8B0C494F8B14524F8B1C5B4F8B24644F8B6C6D004F8B34764F8B3C7F");

	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrBaseIndexDisp32(regA, regA == Register.SP ? Register.AX : regA, SibScale(2), 0x11223344));
	tester.assertHexAndReset("488B848044332211488B8C8944332211488B949244332211488B9C9B44332211488BA48444332211488BACAD44332211488BB4B644332211488BBCBF443322114F8B8480443322114F8B8C89443322114F8B9492443322114F8B9C9B443322114F8BA4A4443322114F8BACAD443322114F8BB4B6443322114F8BBCBF44332211");

	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrBaseDisp8(regA, 0xFE));
	tester.assertHexAndReset("488B40FE488B49FE488B52FE488B5BFE488B6424FE488B6DFE488B76FE488B7FFE4D8B40FE4D8B49FE4D8B52FE4D8B5BFE4D8B6424FE4D8B6DFE4D8B76FE4D8B7FFE");

	foreach (Register regA; Register.min..RegisterMax) tester.movq(regA, memAddrBaseIndexDisp8(regA, regA == Register.SP ? Register.AX : regA, SibScale(3), 0xFE));
	tester.assertHexAndReset("488B44C0FE488B4CC9FE488B54D2FE488B5CDBFE488B64C4FE488B6CEDFE488B74F6FE488B7CFFFE4F8B44C0FE4F8B4CC9FE4F8B54D2FE4F8B5CDBFE4F8B64E4FE4F8B6CEDFE4F8B74F6FE4F8B7CFFFE");
}
